package com.yanqu.road.sync.message;

import com.yanqu.road.pb.syncMessage.SyncMessage;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.protocol.GameErrorCode;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

public class Dispatcher {
    private final AtomicLong sequenceId = new AtomicLong();
    private final Map<Long, ResultProcessor> pendingMap = new ConcurrentHashMap<>();

    public Dispatcher() {

    }

    public ResultProcessor pending(SyncMessage.Request.Builder request) {
        long l = sequenceId.incrementAndGet();
        request.setSequenceId(l);
        ResultProcessor resultProcessor = new ResultProcessor(l);
        pendingMap.put(resultProcessor.getSequenceId(), resultProcessor);
        return resultProcessor;
    }


    public void receive(SyncMessage.Response response) {
        ResultProcessor resultProcessor = pendingMap.remove(response.getSequenceId());
        if (resultProcessor != null) {
            if (resultProcessor.getResponseBuilder() != null) {
                try {
                    resultProcessor.getResponseBuilder().mergeFrom(response.getDataBytes()).buildPartial();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            SyncResponse syncResponse = new SyncResponse();
            syncResponse.setResponseBuilder(resultProcessor.getResponseBuilder());
            syncResponse.setErrorCode(response.getErrorCode());
            resultProcessor.getCompletableFuture().complete(syncResponse);
        }
    }


    public void scheduleCleanResultProcessor() {
        SyncResponse syncResponse = new SyncResponse();
        syncResponse.setErrorCode(GameErrorCode.E_ERROR_TIME_OUT);
        LocalDateTime now = LocalDateTime.now();
        this.pendingMap.forEach((k, v) -> {
            long seconds = Duration.between(v.getCreateAt(), now).getSeconds();
            if (seconds < 5) {
                return;
            }
            ResultProcessor resultProcessor = this.pendingMap.remove(v.getSequenceId());
            if (resultProcessor != null) {
                try {
                    SyncMessage.Request tempMsg = SyncMessage.Request.parseFrom(resultProcessor.getRequest().getMessage().toByteArray());
                    TempMgr.getLogger().error("pending req over time,code:{}", tempMsg.getCmdCode());
                }catch (Exception e){
                    TempMgr.getLogger().error("pending req over time,error", e);
                }
                resultProcessor.getCompletableFuture().complete(syncResponse);
            }
        });
    }

}
